﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using SFP;
using SFP.Animation2D;
using SFP.Audio;
using SFP.Input;
using SFP.CollisionDetection;

namespace TestGame
{
    public class Player
    {
        /* Constants...*/
        const double JUMP_VELOCITY = 500;
        const double MAX_FALL_VELOCITY = 500;

        const double MAX_WALK_VELOCITY = 250;
        const double WALK_ACCELERATION = 1;
        const double WALK_FADE_OUT = 1;

        const double ANIMATION_SPEED = 80;

        /* Player...*/
        public double X { set; get; }
        public double Y { set; get; }
        public double VelocityX { set; get; }
        public double VelocityY { set; get; }
        public bool OnGround { set; get; }
        public bool Jump { set; get; }
        public bool Walking { set; get; }
        public bool GroundCollisionFound { set; get; }

        /* Bitmaps... */
        Bitmap standing_face_left;
        Bitmap standing_face_right;
        Bitmap walking_right_1;
        Bitmap walking_right_2;
        Bitmap walking_right_3;
        Bitmap walking_left_1;
        Bitmap walking_left_2;
        Bitmap walking_left_3;
        Bitmap jump_right;
        Bitmap jump_left;

        /* Image-Animators... */
        ImageSequencer walkingRightSeq;
        ImageSequencer walkingLeftSeq;
        ImageSequencer activeWalkingSeq;
        
        /* Game...*/
        MyGame game;
        LayerManager layerManager;

        public Player(double x, double y, MyGame game)
        {
            X = x;
            Y = y;
            this.game = game;
            this.layerManager = game.GetLayerManager();
        }

        public void loadBitmaps()
        {
            standing_face_right = ContentLoader.LoadBitmap("Content\\standing_face_right.png");
            standing_face_left = ContentLoader.LoadBitmap("Content\\standing_face_left.png");
            walking_right_1 = ContentLoader.LoadBitmap("Content\\walking_right_1.png");
            walking_right_2 = ContentLoader.LoadBitmap("Content\\walking_right_2.png");
            walking_right_3 = ContentLoader.LoadBitmap("Content\\walking_right_3.png");
            walking_left_1 = ContentLoader.LoadBitmap("Content\\walking_left_1.png");
            walking_left_2 = ContentLoader.LoadBitmap("Content\\walking_left_2.png");
            walking_left_3 = ContentLoader.LoadBitmap("Content\\walking_left_3.png");
            jump_right = ContentLoader.LoadBitmap("Content\\jump_right.png");
            jump_left = ContentLoader.LoadBitmap("Content\\jump_left.png");

            walkingRightSeq = new ImageSequencer(new Bitmap[] { walking_right_1, walking_right_2, walking_right_3 },
                                                  ANIMATION_SPEED, new Point(intValue(X), intValue(Y)));
            walkingLeftSeq = new ImageSequencer(new Bitmap[] { walking_left_1, walking_left_2, walking_left_3 },
                                                 ANIMATION_SPEED, new Point(intValue(X), intValue(Y)));
            activeWalkingSeq = walkingRightSeq;
        }

        private int intValue(double value)
        {
            return (int)Math.Round(value, 0, MidpointRounding.AwayFromZero);
        }

        public Rectangle GetRectangle()
        {
            int Width;
            int Height;

            if (OnGround)
            {
                if (Walking)
                {
                    Width = activeWalkingSeq.Width;
                    Height = activeWalkingSeq.Height;
                }
                else
                {
                    if (activeWalkingSeq == walkingRightSeq)
                    {
                        Width = standing_face_right.Width;
                        Height = standing_face_right.Height;
                    }
                    else
                    {
                        Width = standing_face_left.Width;
                        Height = standing_face_left.Height;
                    }
                }
            }
            else
            {
                if (activeWalkingSeq == walkingRightSeq)
                {
                    Width = jump_right.Width;
                    Height = jump_right.Height;
                }
                else
                {
                    Width = jump_left.Width;
                    Height = jump_left.Height;
                }
            }

            return new Rectangle(intValue(X), intValue(Y), Width, Height);
        }

        public void update(double time, KeyboardState keyStates)
        {
            /* Start or stop walking */
            if (keyStates.isKeyDown(Keys.D) && keyStates.isKeyUp(Keys.A))
            {
                Walking = true;

                walkingRightSeq.animate(time, true);
                walkingLeftSeq.resetSequence();
                activeWalkingSeq = walkingRightSeq;

                VelocityX += WALK_ACCELERATION * time;
                if (VelocityX > MAX_WALK_VELOCITY) VelocityX = MAX_WALK_VELOCITY;
            }
            else if (keyStates.isKeyDown(Keys.A) && keyStates.isKeyUp(Keys.D))
            {
                Walking = true;

                walkingLeftSeq.animate(time, true);
                walkingRightSeq.resetSequence();
                activeWalkingSeq = walkingLeftSeq;

                VelocityX -= WALK_ACCELERATION * time;
                if (VelocityX < -MAX_WALK_VELOCITY) VelocityX = -MAX_WALK_VELOCITY;
            }
            else
            {
                Direction hDirection = hMoveDirection();

                if (hDirection == Direction.Right)
                {
                    walkingRightSeq.animate(time, true);
                    walkingLeftSeq.resetSequence();

                    VelocityX -= WALK_FADE_OUT * time;

                    if (VelocityX < 0)
                    {
                        VelocityX = 0;
                    }
                }
                else if (hDirection == Direction.Left)
                {
                    walkingLeftSeq.animate(time, true);
                    walkingRightSeq.resetSequence();

                    VelocityX += WALK_FADE_OUT * time;

                    if (VelocityX > 0)
                    {
                        VelocityX = 0;
                    }
                }
                else if (hDirection == Direction.None)
                {
                    walkingRightSeq.resetSequence();
                    walkingLeftSeq.resetSequence();
                    Walking = false;
                }
            }

            /* Start or stop jump */
            if (keyStates.isKeyDownNotPressed(Keys.Space))
            {
                if (OnGround)
                {
                    VelocityY = JUMP_VELOCITY + time/2;
                    Jump = true;
                    OnGround = false;
                    AudioPlayer.play(Ressources.JUMP_SOUND, true);
                }
            }
            if (keyStates.isKeyUp(Keys.Space))
            {
                if (Jump && VelocityY > 0) VelocityY = 0;
                Jump = false;
            }

            /* Gravity */
            if (!OnGround) VelocityY -= MyGame.GRAVITY * time / 1000;
            else VelocityY = 0;
            if (VelocityY < -MAX_FALL_VELOCITY) VelocityY = -MAX_FALL_VELOCITY;

            /* Position */
            X += VelocityX * time / 1000;
            Y -= VelocityY * time / 1000;

            if (X < 0)
                X = 0;
            else if (X + activeWalkingSeq.Width > game.resolution.Width)
                X = game.resolution.Width - activeWalkingSeq.Width;

            int resolutionHalfWidth = game.resolution.Width / 2;
            if (!layerManager.isXAtEnd() && X > resolutionHalfWidth)
            {
                X = resolutionHalfWidth;
                layerManager.scrollX(VelocityX * (time / 1000));
            }
            if (!layerManager.isXAtBeginn() && X < resolutionHalfWidth)
            {
                X = resolutionHalfWidth;
                layerManager.scrollX(VelocityX * (time / 1000));
            }

            int resolutionHalfHeight = game.resolution.Height / 2;
            if (!layerManager.isYAtEnd() && Y < resolutionHalfHeight && !OnGround)
            {
                Y = resolutionHalfHeight;
                layerManager.scrollY(VelocityY * (time / 1000));
            }
            if (!layerManager.isYAtBeginn() && Y > resolutionHalfHeight && !OnGround)
            {
                Y = resolutionHalfHeight;
                layerManager.scrollY(VelocityY * (time / 1000));
            }

            /* Collision detection */
            GroundCollisionFound = false;
            
            long itemBlockSetID = Collision.collisionsForGameObjects(GameObjects.ItemBlocks, GetRectangle(), true);
            long blockSetID = Collision.collisionsForGameObjects(GameObjects.Blocks, GetRectangle(), true);
            long coinSetID = Collision.collisionsForGameObjects(GameObjects.Coins, GetRectangle(), false);

            Collision.processFilters(vMoveDirection(), hMoveDirection());
            
            CollisionReactions.ItemBlockReaction.reactToCollision(itemBlockSetID);
            CollisionReactions.BlockReaction.reactToCollision(blockSetID);
            CollisionReactions.CoinReaction.reactToCollision(coinSetID);
            CollisionReactions.ObstaclekReaction.reactToCollision(new long[] { itemBlockSetID, blockSetID });

            if (!GroundCollisionFound) OnGround = false;

            /* Set position for animations */
            walkingRightSeq.Position = new Point(intValue(X), intValue(Y));
            walkingLeftSeq.Position = new Point(intValue(X), intValue(Y));
        }

        public Direction vMoveDirection()
        {
            if (VelocityY > 0) return Direction.Up;
            else if (VelocityY < 0) return Direction.Down;

            return Direction.None;
        }

        public Direction hMoveDirection()
        {
            if (VelocityX < 0) return Direction.Left;
            else if (VelocityX > 0) return Direction.Right;

            return Direction.None;
        }

        public void draw(Graphics g)
        {
            if (!OnGround)
            {
                if (activeWalkingSeq == walkingLeftSeq)
                    g.DrawImage(jump_left, intValue(X), intValue(Y - jump_left.Height));
                else
                    g.DrawImage(jump_right, intValue(X), intValue(Y - jump_left.Height));
            }
            else if (Walking)
            {
                activeWalkingSeq.draw(g);
            }
            else
            {
                if (activeWalkingSeq == walkingRightSeq)
                    g.DrawImage(standing_face_right, intValue(X), intValue(Y - standing_face_right.Height));
                else
                    g.DrawImage(standing_face_left, intValue(X), intValue(Y - standing_face_left.Height));
            }

            g.FillRectangle(Brushes.Black, 5, 30, 140, 55);
            g.DrawString("X=" + Math.Round(X, 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 5, 30);
            g.DrawString("Y=" + Math.Round(Y, 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 5, 42);
            g.DrawString("VX=" + Math.Round(VelocityX, 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 78, 30);
            g.DrawString("VY=" + Math.Round(VelocityY, 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 78, 42);
            g.DrawString("SX=" + Math.Round(layerManager.getXScroll(), 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 5, 54);
            g.DrawString("SY=" + Math.Round(layerManager.getYScroll(), 2), new Font("Arial", 9), new SolidBrush(Color.Yellow), 78, 54);
        }
    }
}
